//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#if !defined(__EZSTRTOKEN_H__)
#define __EZSTRTOKEN_H__

#define TOKEN_HEAP_ALLOC_THRESHOLD 256

#ifdef __cplusplus

class WStringTokenizer;
class AStringTokenizer;

extern "C" {
    _ELASTOS Boolean __cdecl _WStringTokenizer_HasMoreTokens(
        WStringTokenizer *pTokenizer);
    _ELASTOS Boolean __cdecl _AStringTokenizer_HasMoreTokens(
        AStringTokenizer *pTokenizer);
    _ELASTOS Int32 __cdecl _WStringTokenizer_GetCount(
        WStringTokenizer *pTokenizer);
    _ELASTOS Int32 __cdecl _AStringTokenizer_GetCount(
        AStringTokenizer *pTokenizer);
    wchar_t* __cdecl _WStringTokenizer_NextToken(
        WStringTokenizer *pTokenizer);
    char* __cdecl _AStringTokenizer_NextToken(AStringTokenizer *pTokenizer);
}

class WStringTokenizer
{
friend _ELASTOS Boolean __cdecl _WStringTokenizer_HasMoreTokens(
        WStringTokenizer *pTokenizer);
friend _ELASTOS Int32 __cdecl _WStringTokenizer_GetCount(
        WStringTokenizer *pTokenizer);
friend wchar_t* __cdecl _WStringTokenizer_NextToken(
        WStringTokenizer *pTokenizer);

public:
    WStringTokenizer(_ELASTOS WString str,
        _ELASTOS WString delim = L" \t\n\r\f",
        _ELASTOS Boolean returnDelims = FALSE)
    {
        m_curPos = str;
        assert(m_curPos);
        m_delimiters = delim;
        m_retDelims = returnDelims;
        m_delimsChanged = TRUE;
        m_newPos = NULL;
        m_pBuf = NULL;
        m_bufSize = TOKEN_HEAP_ALLOC_THRESHOLD * 2 - 1;
    }

    _ELASTOS Int32 GetCount()
    {
        return _WStringTokenizer_GetCount(this);
    }

    _ELASTOS Boolean HasMoreTokens()
    {
        if (!m_curPos || *m_curPos == L'\0') return FALSE;
        return _WStringTokenizer_HasMoreTokens(this);
    }

    _ELASTOS WString NextToken()
    {
        if (!m_curPos || *m_curPos == L'\0') return NULL;
        return _WStringTokenizer_NextToken(this);
    }

    _ELASTOS WString NextToken(_ELASTOS WString delim)
    {
        m_delimiters = delim;
        m_delimsChanged = TRUE;
        return NextToken();
    }

    WStringTokenizer& operator>>(_ELASTOS AStringBuf& asb)
    {
        asb.Copy(NextToken());
        return *this;
    }

    WStringTokenizer& operator>>(_ELASTOS WStringBuf& wsb)
    {
        wsb.Copy(NextToken());
        return *this;
    }

    WStringTokenizer& operator>>(_ELASTOS Boolean& boolean)
    {
        boolean = NextToken().ToBoolean();
        return *this;
    }

    WStringTokenizer& operator>>(_ELASTOS Int32& value)
    {
        value = NextToken().ToInt32();
        return *this;
    }

    WStringTokenizer& operator>>(_ELASTOS Int64& value)
    {
        value = NextToken().ToInt64();
        return *this;
    }

    WStringTokenizer& operator>>(_ELASTOS Double& value)
    {
        value = NextToken().ToDouble();
        return *this;
    }

    ~WStringTokenizer()
    {
        if (m_pBuf) free(m_pBuf);
    }

private:
    WStringTokenizer() {}

    const wchar_t *m_curPos;
    const wchar_t *m_newPos;
    const wchar_t *m_delimiters;
    wchar_t *m_pBuf;
    _ELASTOS Int32 m_bufSize;
    _ELASTOS Boolean m_retDelims;
    _ELASTOS Boolean m_delimsChanged;
    wchar_t m_tokenBuf[TOKEN_HEAP_ALLOC_THRESHOLD];
};

class AStringTokenizer
{
friend _ELASTOS Boolean __cdecl _AStringTokenizer_HasMoreTokens(
        AStringTokenizer *pTokenizer);
friend _ELASTOS Int32 __cdecl _AStringTokenizer_GetCount(
        AStringTokenizer *pTokenizer);
friend char* __cdecl _AStringTokenizer_NextToken(
        AStringTokenizer *pTokenizer);

public:
    AStringTokenizer(_ELASTOS AString str, _ELASTOS AString delim = " \t\n\r\f",
        _ELASTOS Boolean returnDelims = FALSE)
    {
        m_curPos = str;
        assert(m_curPos);
        m_delimiters = delim;
        m_retDelims = returnDelims;
        m_delimsChanged = TRUE;
        m_newPos = NULL;
        m_pBuf = NULL;
        m_bufSize = TOKEN_HEAP_ALLOC_THRESHOLD * 2 - 1;
    }

    _ELASTOS Int32 GetCount()
    {
        return _AStringTokenizer_GetCount(this);
    }

    _ELASTOS Boolean HasMoreTokens()
    {
        if (!m_curPos || *m_curPos == '\0') return FALSE;
        return _AStringTokenizer_HasMoreTokens(this);
    }

    _ELASTOS AString NextToken()
    {
        if (!m_curPos || *m_curPos == '\0') return NULL;
        return _AStringTokenizer_NextToken(this);
    }

    _ELASTOS AString NextToken(_ELASTOS AString delim)
    {
        m_delimiters = delim;
        m_delimsChanged = TRUE;
        return NextToken();
    }

    AStringTokenizer& operator>>(_ELASTOS AStringBuf& asb)
    {
        asb.Copy(NextToken());
        return *this;
    }

    AStringTokenizer& operator>>(_ELASTOS WStringBuf& wsb)
    {
        wsb.Copy(NextToken());
        return *this;
    }

    AStringTokenizer& operator>>(_ELASTOS Boolean& boolean)
    {
        boolean = NextToken().ToBoolean();
        return *this;
    }

    AStringTokenizer& operator>>(_ELASTOS Int32& value)
    {
        value = NextToken().ToInt32();
        return *this;
    }

    AStringTokenizer& operator>>(_ELASTOS Int64& value)
    {
        value = NextToken().ToInt64();
        return *this;
    }

    AStringTokenizer& operator>>(_ELASTOS Double& value)
    {
        value = NextToken().ToDouble();
        return *this;
    }

    ~AStringTokenizer()
    {
        if (m_pBuf) free(m_tokenBuf);
    }

private:
    AStringTokenizer() {}

    const char *m_curPos;
    const char *m_newPos;
    const char *m_delimiters;
    char *m_pBuf;
    _ELASTOS Int32   m_bufSize;
    _ELASTOS Boolean m_retDelims;
    _ELASTOS Boolean m_delimsChanged;
    char m_tokenBuf[TOKEN_HEAP_ALLOC_THRESHOLD];
};

#else //!__cplusplus

typedef const _ELASTOS PVoid WStringTokenizer;

#endif //__cplusplus

#endif //__EZSTRTOKEN_H__
